import math

pi = 3.1415926535897932384626
a = 6378245.0
ee = 0.00669342162296594323


def transform_lat(x, y):
    ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * math.sqrt(math.fabs(x))
    ret += (20.0 * math.sin(6.0 * x * pi) + 20.0 * math.sin(2.0 * x * pi)) * 2.0 / 3.0
    ret += (20.0 * math.sin(y * pi) + 40.0 * math.sin(y / 3.0 * pi)) * 2.0 / 3.0
    ret += (160.0 * math.sin(y / 12.0 * pi) + 320 * math.sin(y * pi / 30.0)) * 2.0 / 3.0
    return ret


def transform_lon(x, y):
    ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * math.sqrt(math.fabs(x))
    ret += (20.0 * math.sin(6.0 * x * pi) + 20.0 * math.sin(2.0 * x * pi)) * 2.0 / 3.0
    ret += (20.0 * math.sin(x * pi) + 40.0 * math.sin(x / 3.0 * pi)) * 2.0 / 3.0
    ret += (150.0 * math.sin(x / 12.0 * pi) + 300.0 * math.sin(x / 30.0 * pi)) * 2.0 / 3.0
    return ret


def transform(lon, lat):
    d_lat = transform_lat(lon - 105.0, lat - 35.0)
    d_lon = transform_lon(lon - 105.0, lat - 35.0)
    rad_lat = lat / 180.0 * pi
    magic = math.sin(rad_lat)
    magic = 1 - ee * magic * magic
    sqrt_magic = math.sqrt(magic)
    d_lat = (d_lat * 180.0) / ((a * (1 - ee)) / (magic * sqrt_magic) * pi)
    d_lon = (d_lon * 180.0) / (a / sqrt_magic * math.cos(rad_lat) * pi)
    mg_lat = lat + d_lat
    mg_lon = lon + d_lon
    return [mg_lon, mg_lat]


def gcj_to_gps84(lon, lat):
    gps = transform(lon, lat)
    lontitude = lon * 2 - gps[0]
    latitude = lat * 2 - gps[1]
    return [round(lontitude, 6), round(latitude, 6)]


def gps84_to_gcj02(lon, lat):
    d_lat = transform_lat(lon - 105.0, lat - 35.0)
    d_lon = transform_lon(lon - 105.0, lat - 35.0)
    rad_lat = lat / 180.0 * pi
    magic = math.sin(rad_lat)
    magic = 1 - ee * magic * magic
    sqrt_magic = math.sqrt(magic)
    d_lat = (d_lat * 180.0) / ((a * (1 - ee)) / (magic * sqrt_magic) * pi)
    d_lon = (d_lon * 180.0) / (a / sqrt_magic * math.cos(rad_lat) * pi)
    mg_lat = lat + d_lat
    mg_lon = lon + d_lon
    return [mg_lon, mg_lat]


def gcj02_to_bd09(lon, lat):
    x = lon
    y = lat
    z = math.sqrt(x * x + y * y) + 0.00002 * math.sin(y * pi)
    theta = math.atan2(y, x) + 0.000003 * math.cos(x * pi)
    bd_lon = z * math.cos(theta) + 0.0065
    bd_lat = z * math.sin(theta) + 0.006
    return [bd_lon, bd_lat]


def gps84_to_bd09(lon, lat):
    gcj = gps84_to_gcj02(lon, lat)
    return gcj02_to_bd09(gcj[0], gcj[1])


def bd09_to_gcj02(lon, lat):
    x = lon - 0.0065
    y = lat - 0.006
    z = math.sqrt(x * x + y * y) - 0.00002 * math.sin(y * pi)
    theta = math.atan2(y, x) - 0.000003 * math.cos(x * pi);
    gg_lon = z * math.cos(theta)
    gg_lat = z * math.sin(theta)
    return [gg_lon, gg_lat]


def bd09_to_gps84(lon, lat):
    gcj = bd09_to_gcj02(lon, lat)
    return gcj_to_gps84(gcj[0], gcj[1])


def mercator_to_wgs84(x, y):
    lon = x/20037508.34*180
    lat = y/20037508.34*180
    lat = 180/math.pi * (2 * math.atan(math.exp(lat*math.pi/180))-math.pi/2)
    return [lon, lat]


def wgs84_to_mercator(lon, lat):
    x = lon*20037508.342789/180
    y = math.log(math.tan((90+lat)*math.pi/360))/(math.pi/180)
    y = y * 20037508.34789 / 180
    return [x, y]

